package cn.ad.server.job.adapter.persistence.job;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.Resource;

import cn.ad.server.job.adapter.dbaccess.AssembledCachedDataContainer;
import cn.ad.server.job.domain.job.AdSpaceRepositoryService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Repository;

import cn.ad.server.persistence.dao.AdMaterialDao;
import cn.ad.server.persistence.dao.AdMaterialGroupDao;
import cn.ad.server.persistence.dao.AdSizeDao;
import cn.ad.server.persistence.dao.AdSpaceDao;
import cn.ad.server.persistence.dao.AdTemplateDao;
import cn.ad.server.persistence.dao.AdTemplateSpecDao;
import cn.ad.server.persistence.dao.AppClassDao;
import cn.ad.server.persistence.dao.CampaignDao;
import cn.ad.server.persistence.dao.CreativeDao;
import cn.ad.server.persistence.dao.DayPartingDao;
import cn.ad.server.persistence.dao.InteractionAppDao;
import cn.ad.server.persistence.dao.InteractionRedirectsDao;
import cn.ad.server.persistence.dao.PubSiteDao;
import cn.ad.server.persistence.dao.RatioDao;
import cn.ad.server.persistence.dao.StrategyCrowdMapDao;
import cn.ad.server.persistence.dao.StrategyDao;
import cn.ad.server.persistence.dao.StrategyDeviceMapDao;
import cn.ad.server.persistence.dao.StrategyGeoMapDao;
import cn.ad.server.domain.ad.AdMaterial;
import cn.ad.server.domain.ad.AdMaterialGroup;
import cn.ad.server.domain.ad.AdSize;
import cn.ad.server.domain.ad.AdSpace;
import cn.ad.server.domain.ad.AdTemplate;
import cn.ad.server.domain.ad.AdTemplateSpec;
import cn.ad.server.domain.ad.AppClass;
import cn.ad.server.domain.ad.AuditPassedMarker;
import cn.ad.server.domain.ad.Campaign;
import cn.ad.server.domain.ad.Creative;
import cn.ad.server.domain.ad.DayTargert;
import cn.ad.server.domain.ad.InteractionApp;
import cn.ad.server.domain.ad.InteractionRedirects;
import cn.ad.server.domain.ad.PubSite;
import cn.ad.server.domain.ad.Ratio;
import cn.ad.server.domain.ad.Strategy;
import cn.ad.server.domain.ad.StrategyGeoMap;
import cn.ad.server.domain.enumration.AdFormat;

@Repository
public class AdSpaceRepositoryServant implements AdSpaceRepositoryService {
	private static Logger logger = LoggerFactory.getLogger(AdSpaceRepositoryServant.class);

	public final static int STATUS_VALID = 1;
	@Autowired
	private AdSpaceDao adSpaceDao;

	@Autowired
	private RatioDao ratioDao;

	@Autowired
	private PubSiteDao pubSiteDao;

	@Autowired
	private CreativeDao creativeDao;

	@Autowired
	private StrategyDao strategyDao;

	@Autowired
	private AdMaterialGroupDao adMaterialGroupDao;

	@Autowired
	private AdMaterialDao adMaterialDao;

	@Autowired
	private StrategyGeoMapDao strategyGeoMapDao;

	@Autowired
	private DayPartingDao dayPartingDao;

	@Autowired
	private InteractionRedirectsDao interactionRedirectsDao;

	@Autowired
	private InteractionAppDao interactionAppDao;

	@Autowired
	private AppClassDao appClassDao;

	@Autowired
	private AdSizeDao adSizeDao;

	@Autowired
	private CampaignDao campaignDao;

	@Autowired
	private AdTemplateSpecDao adTemplateSpecDao;

	@Autowired
	private AdTemplateDao adTemplateDao;

	@Autowired
	private StrategyCrowdMapDao strategyCrowdMapDao;
	
	@Autowired
	private StrategyDeviceMapDao strategyDeviceMapDao;
	
	@Resource(name = "cacheRedisTemplate")
	private RedisTemplate<String, AdSpace> redisTemplate;

	@Resource(name = "cacheRedisTemplate")
	private ValueOperations<String, AdSpace> adSpaceValueOperations;

	@Resource(name = "cacheRedisTemplate")
	private ValueOperations<String, AdSize> adSizeValueOperations;

	@Resource(name = "cacheRedisTemplate")
	private ValueOperations<String, Ratio> ratioValueOperations;

	@Resource(name = "cacheRedisTemplate")
	private ValueOperations<String, String> stringValueOperations;

//	@Resource(name = "cacheRedisTemplate")
//	private ValueOperations<String, GuidValueObject> guidValueOperations;

	@Resource(name = "cacheRedisTemplate")
	private ValueOperations<String, Long> counterOperations;



	/***************************** 以下新加 **************************************************/
	
	@Autowired
	private AssembledCachedDataContainer container;
	
	
	private ConcurrentHashMap<Integer, StrategyWarmUpServant.StrategyGoupMap> mapStrategyGroupAll;

	/**
	 * 非法数据和不是有效数据删除。有效数据插入
	 */
	@Override
	public void warmUpAllAssociation() {
		this.mapStrategyGroupAll = container.getMapStrategyGroupAll();
		List<AdSpace> adSpaces = null;
		adSpaces = adSpaceDao.findAll();
		for (AdSpace adSpace : adSpaces) {
			try {
//				if(adSpace.getId() ==222){
//					System.out.println("210");
//				}
				if (adSpace.getStatus() == 1) {
					AdSpace _adSpace = attachAdSpaceAssociation(adSpace);
					if (_adSpace != null) {
						adSpaceValueOperations.set(_adSpace.toCacheKey(), _adSpace);
					} else {// 非法数据
						redisTemplate.delete(adSpace.toCacheKey());
					}
				} else if (adSpace.getStatus() != 1) {
					redisTemplate.delete(adSpace.toCacheKey());
				}
			} catch (Exception e) {
				if (adSpace != null) {
					logger.error("错误：在获取adspace_id =" + adSpace.getId() + "数据时发生错误 \n 错误信息：", e);
				}
			}
		}
	}


	/**
	 * 根据简单广告位对象。添附上相关联的数据。
	 * 
	 * @param adsp
	 * @return
	 */
	private AdSpace attachAdSpaceAssociation(AdSpace adsp) {
		AdSpace adSpace = adsp;

		if (adSpace == null) {
			return null;
		}

		if (adSpace.getAdFormat() == null) {
			logger.warn("非法数据 :  AdFormat 为null 在 (" + adSpace.getId() + ")adSpace对象中");
			return null;
		}

		if (adSpace.getAdFormat() == AdFormat.AD_NATIVE) {
			if (adSpace.getAdTemplate() == null) {
				logger.warn("非法数据 :  AdTemplate 为null 在(" + adSpace.getId() + ")adSpace原生类型对象中");
				return null;
			}
		}

		if (adSpace.getRatio() != null) {
			Ratio ratio = ratioDao.selectById(adSpace.getRatio().getId(), STATUS_VALID);
			adSpace.setRatio(ratio);
		}
		if (adSpace.getPubSite() != null) {
			PubSite pubSite = pubSiteDao.selectById(adSpace.getPubSite().getId(), STATUS_VALID);
			adSpace.setPubSite(pubSite);
		}

		// 默认创意
		if (adSpace.getDefaultCreativeOption() == 0) {
			adSpace.setDefaultCreative(null);
		} else {
			Creative defaultCreative = adSpace.getDefaultCreative();
			if (defaultCreative != null) {
				adSpace.setDefaultCreative(getCreativeByIdFrmDB(defaultCreative.getId(), adSpace));
			} else {
				adSpace.setDefaultCreative(null);
			}
		}

		List<Strategy> strategys = getStrategyByAdSpaceIdFrmDB(adSpace.getId(), adSpace);
		adSpace.setStrategys(strategys);
		return adSpace;
	}

	/**
	 * 获取有效的Creative
	 * 
	 * @param id
	 * @param adSpace
	 * @return
	 */
	private Creative getCreativeByIdFrmDB(long id, AdSpace adSpace) {
		try {
			Creative creative = creativeDao.selectById(id, STATUS_VALID);
			if (creative == null) {
				return null;
			}

			// if(creative.getAdFormat()==null){
			// return null;
			// }

			// FIXME
			if (creative.getAdFormat() != adSpace.getAdFormat()) {
				// logger.warn( "非法数据 :
				// ("+creative.getId()+")creative.AdFormat不等于("+adSpace.getId()+")adSpace.AdFormat
				// " );
				return null;
			}

			if (creative.getAdFormat() == AdFormat.AD_NATIVE) {
				//判断是否审核通过。
				List<AuditPassedMarker> auditPassedMarkers = creative.getAuditPassedMarkers();
				if(auditPassedMarkers==null||auditPassedMarkers.isEmpty()){
					return null;
				}
				
				// 加载adMaterialGroups
				// List<AdMaterialGroup> adMaterialGroups =
				// adMaterialGroupDao.selectByCreativeId(creative.getId(),STATUS_VALID);
				List<AdMaterialGroup> adMaterialGroups = adMaterialGroupDao.selectByCreativeIdNdTemplateId(
						creative.getId(), adSpace.getAdTemplate().getId(), STATUS_VALID);
				if (adMaterialGroups == null || adMaterialGroups.size() == 0) {
					// logger.warn( "非法数据 : 从数据库 根据 CreativeId
					// ("+creative.getId()+")和adSpace("+adSpace.getId()+")中TemplateId("+adSpace.getAdTemplate().getId()+")没有发现AdMaterialGroup对象");
					return null;
				}
				for (AdMaterialGroup adMaterialGroup : adMaterialGroups) {
					getDetailAdMaterialGroup(adMaterialGroup);
				}
				creative.setAdMaterialGroups(adMaterialGroups);
				// 加载adTemplate
				AdTemplate adTemplate = adSpace.getAdTemplate();
				adTemplate = getAdTemplate(adTemplate);
				if (adTemplate == null) {
					logger.warn("非法数据 : 在 原生 adSpace(" + adSpace.getId() + ") 没有 Template 对象");
				}
				creative.setAdTemplate(adTemplate);
			} else {
				// 加载adMaterials
				List<AdMaterial> adMaterials = adMaterialDao.selectAllByCreativeId(creative.getId(), STATUS_VALID);
				List<AdMaterial> adMaterialOks = new ArrayList<>();
				for (AdMaterial adMaterial : adMaterials) {
					AdMaterial m = getDetailAdMaterial(adMaterial);
					if(m==null){						
						continue;
					}
					//判断是否审核通过。
					m = getAuditPassedAdMaterial(m);
					if(m==null){						
						continue;
					}
					adMaterialOks.add(m);
				}
				
				//没有审核通过素材的creative无效。
				if(adMaterialOks.isEmpty()){
					return null;
				}
				creative.setAdMaterials(adMaterialOks);
			}

			// 0 无交互 1 跳转 2 APP下载 3
			if (creative.getInteractionType() == 1) {
				InteractionRedirects interactionRedirect = interactionRedirectsDao
						.findById(creative.getInteractionId());
				creative.setInteractionRedirects(interactionRedirect);
			} else if (creative.getInteractionType() == 2) {
				InteractionApp interactionApp = interactionAppDao.findById(creative.getInteractionId());
				if (interactionApp != null) {
					// 默认取两级
					AppClass appClass = appClassDao.findById(interactionApp.getClassesId());
					interactionApp.setAppClass(appClass);
					if (appClass != null && appClass.getParentId() != 0) {
						AppClass parentAppClass = appClassDao.findById(appClass.getParentId());
						appClass.setParentAppClass(parentAppClass);
					}
				}
				creative.setInteractionApp(interactionApp);
			}
			return creative;
		} catch (Exception e) {
			logger.error("错误: creative_id=" + id + "发生错误。");
			throw e;
		}
	}

	/**
	 * 获取详细的AdMaterialGroup
	 * 
	 * @param adMaterialGroup
	 * @return
	 */
	private AdMaterialGroup getDetailAdMaterialGroup(AdMaterialGroup adMaterialGroup) {
		AdMaterial adMaterial = adMaterialGroup.getAdMaterial();
		if (adMaterial != null) {
			adMaterial = adMaterialDao.selectById(adMaterial.getId(), STATUS_VALID);		
			getDetailAdMaterial(adMaterial);
			adMaterialGroup.setAdMaterial(adMaterial);
		} else {
			adMaterialGroup.setAdMaterial(null);
		}

		AdTemplateSpec adTemplateSpec = adMaterialGroup.getAdTemplateSpec();
		if (adTemplateSpec != null) {
			adTemplateSpec = adTemplateSpecDao.selectById(adTemplateSpec.getId(), STATUS_VALID);
			adMaterialGroup.setAdTemplateSpec(adTemplateSpec);
		} else {
			adMaterialGroup.setAdTemplateSpec(null);
		}
//现在只使用创意级别的交互。不做素材组的交互。
//		// 0 无交互 1 跳转 2 APP下载 3
//		if (adMaterialGroup.getInteractionType() == 1) {
//			InteractionRedirects interactionRedirect = interactionRedirectsDao
//					.findById(adMaterialGroup.getInteractionId());
//			adMaterialGroup.setInteractionRedirects(interactionRedirect);
//		} else if (adMaterialGroup.getInteractionType() == 2) {
//			InteractionApp interactionApp = interactionAppDao.findById(adMaterialGroup.getInteractionId());
//			if (interactionApp != null) {
//				// 默认取两级
//				AppClass appClass = appClassDao.findById(interactionApp.getClassesId());
//				interactionApp.setAppClass(appClass);
//				if (appClass != null && appClass.getParentId() != 0) {
//					AppClass parentAppClass = appClassDao.findById(appClass.getParentId());
//					appClass.setParentAppClass(parentAppClass);
//				}
//			}
//			adMaterialGroup.setInteractionApp(interactionApp);
//		}

		return adMaterialGroup;
	}

	/**
	 * 根据id获得AdTemplate
	 * 
	 * @param adTemplate
	 * @return
	 */
	private AdTemplate getAdTemplate(AdTemplate adTemplate) {
		adTemplate = adTemplateDao.selectById(adTemplate.getId(), STATUS_VALID);
		return adTemplate;
	}

	/**
	 * 获取详细的AdMaterial
	 * 
	 * @param adMaterial
	 * @return
	 */
	private AdMaterial getDetailAdMaterial(AdMaterial adMaterial) {
		if (adMaterial == null) {
			return null;
		}
		// adSize
		AdSize adSize = adMaterial.getAdSize();
		if (adSize != null) {
			adSize = adSizeDao.selectById(adMaterial.getAdSize().getId(), STATUS_VALID);
			adMaterial.setAdSize(adSize);
		}

		return adMaterial;
	}
	
	/**
	 * 获取审核通过的adMaterial
	 * 
	 * @param adMaterial
	 * @return
	 */
	private AdMaterial getAuditPassedAdMaterial(AdMaterial adMaterial) {
		if (adMaterial == null) {
			return null;
		}
		List<AuditPassedMarker> auditPassedMarkers = adMaterial.getAuditPassedMarkers();
		if(auditPassedMarkers==null|auditPassedMarkers.isEmpty()){
			return null;
		}
		
		return adMaterial;
	}

	/**
	 * 根据广告位id获得有效的Strategy列表
	 * 
	 * @param id
	 * @param adSpace
	 * @return
	 */
	private List<Strategy> getStrategyByAdSpaceIdFrmDB(long id, AdSpace adSpace) {
		List<Strategy> strategys = new ArrayList<>();
		List<Integer> strategyIds = strategyDao.selectSpaceId(id, STATUS_VALID);
		long currentTimeMillis = System.currentTimeMillis();
		for (Integer strategyId : strategyIds) {
			try {
				Strategy s = strategyDao.selectById(strategyId, STATUS_VALID);
				if (s == null) {
					continue;
				}
//				if(adSpace.getId()==36){//s.getId()==10&&
//					System.out.println();
//				}
				//投放结束的策略不load
				if(s.getEndTime().getTime()<currentTimeMillis){
					continue;
				}

				/**
				 * 订单 如果订单存在或status！=1 则这个策略无效为null
				 */
				Campaign campaign = s.getCampaign();
				if (campaign != null) {
					Campaign _campaign = campaignDao.selectById(campaign.getId(), STATUS_VALID);
					if (_campaign == null) {
						continue;
					}
					//投放结束的订单不load
					if(_campaign.getEndTime().getTime()<currentTimeMillis){
						continue;
					}
					
					s.setCampaign(_campaign);
				}else{
					//订单无效时 不load
					continue;
				}
				/**
				 * 根据strategyGroupId添加分组。
				 */
				
				attachGroup(s);
				
				strategys.add(s);
			} catch (Exception e) {
				logger.error("错误: 执行strategy_Id=" + strategyId + "数据获取订单发生错误。");
				throw e;
			}
		}
		
		
		

		for (Strategy strategy : strategys) {

//			if(strategy.getId()==10&&adSpace.getId()==222){
//				System.out.println();
//			}
			long strategyId = strategy.getId();

			try {
				strategy.setDeviceTargert(strategyDeviceMapDao.selectByStrategyId(strategyId, STATUS_VALID));
				
				strategy.setCrowdTargert(strategyCrowdMapDao.selectByStrategyId(strategyId, STATUS_VALID));

				/**
				 * 地域定向
				 */
				List<Integer> countrys = new ArrayList<>();
				strategy.setGeoCountryTargert(countrys);
				List<Integer> states = new ArrayList<>();
				strategy.setGeoStateTargert(states);
				List<Integer> citys = new ArrayList<>();
				strategy.setGeoCityTargert(citys);
				List<Integer> districts = new ArrayList<>();
				strategy.setGeoDistrictTargert(districts);

				List<StrategyGeoMap> geos = strategyGeoMapDao.selectGeo(strategyId, STATUS_VALID);
				for (StrategyGeoMap geoMap : geos) {
					int type = geoMap.getGeoType();
					int geoId = geoMap.getGeoId();
					// 0 国家 对应geo_country， 1 省/州 对应geo_state, 2 城市 对应geo_cidy, 3
					// 省份分区 对应geo_district',
					if (type == 0) {
						countrys.add(geoId);
					} else if (type == 1) {
						states.add(geoId);
					} else if (type == 2) {
						citys.add(geoId);
					} else if (type == 3) {
						districts.add(geoId);
					}
				}

				/**
				 * 时间定向 当没有数据给定默认。当获取到DayTargert中全为0更改为全投
				 */
				List<DayTargert> dayTargerts = dayPartingDao.selectAllByStrategyId(strategyId, STATUS_VALID);
				if (dayTargerts.size() > 0) {
					DayTargert dayTargert = dayTargerts.get(0);

					if (dayTargert.getMonday() == 0 && dayTargert.getTuesday() == 0 && dayTargert.getWednesday() == 0
							&& dayTargert.getThursday() == 0 && dayTargert.getFriday() == 0
							&& dayTargert.getSaturday() == 0 && dayTargert.getSunday() == 0) {
						int allHours = 16777215;
						dayTargert.setMonday(allHours);
						dayTargert.setTuesday(allHours);
						dayTargert.setWednesday(allHours);
						dayTargert.setThursday(allHours);
						dayTargert.setFriday(allHours);
						dayTargert.setSaturday(allHours);
						dayTargert.setSunday(allHours);
						strategy.setDayTargert(dayTargert);
					}
					strategy.setDayTargert(dayTargert);
				} else {
					// 如果没有则默认一周这个时间段全投放
					DayTargert dayTargert = new DayTargert();
					int allHours = 16777215;
					dayTargert.setMonday(allHours);
					dayTargert.setTuesday(allHours);
					dayTargert.setWednesday(allHours);
					dayTargert.setThursday(allHours);
					dayTargert.setFriday(allHours);
					dayTargert.setSaturday(allHours);
					dayTargert.setSunday(allHours);
					strategy.setDayTargert(dayTargert);
				}

				/**
				 * 创意
				 */
				List<Integer> creativeIds = strategyDao.selectCreativeId(strategyId, STATUS_VALID);
				List<Creative> creatives = new ArrayList<>();
				for (Integer creativeId : creativeIds) {
					Creative creative = getCreativeByIdFrmDB(creativeId, adSpace);
					if (creative != null) {
						creatives.add(creative);
					}
				}
				if (creatives.size() == 0) {
//					logger.warn("非法数据 : adSpace(" + adSpace.getId() + ")对象下strategy(" + strategy.getId() + ")没有有效的创意");
				}
				strategy.setCreatives(creatives);
			} catch (Exception e) {
				logger.error("错误: 执行strategy_Id=" + strategyId + "数据发生错误。");
				throw e;
			}
		}
		
		//移除空创意的策略。
		for (int i = 0; i < strategys.size(); i++) {
			if(strategys.get(i).getCreatives().isEmpty()){
//				if(strategys.get(i).getId()==10&&adSpace.getId()==222){
//					System.out.println();
//				}
				strategys.remove(i);
				i--;
			}
		}

		return strategys;

	}
	
	private void attachGroup(Strategy strategy) {
		if(strategy==null){
			return ;	
		}
		if (strategy.getStrategyGroupId()==0) {
			return;
		}
		StrategyWarmUpServant.StrategyGoupMap strategyGoupMap = mapStrategyGroupAll.get(strategy.getStrategyGroupId());
		if(strategyGoupMap!=null){			
			strategy.setStrategyGroup(strategyGoupMap.getGroup());
		}
		
	}
}
